package com.atguigu.demo03_redis.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Arrays;

@Service
public class SecondKillService {
//    @Autowired
//    RedisTemplate redisTemplate;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
//    public String secondKill(String skuId) {
//        // 1000个请求 会生成1000个redis的 decr key命令 交给redis
//        // redis使用单个线程接受处理： 它会一个个执行命令，下一个命令使用的库存一定是上一个命令计算完的结果
////        stringRedisTemplate.opsForValue().decrement("sec:skuId:"+skuId);
//
//        //1、查询库存：如果库存不足 返回秒杀失败
//        String stockStr = stringRedisTemplate.opsForValue().get("sec:skuId:" + skuId);
//        if(StringUtils.isEmpty(stockStr)) {
//            return "库存还未初始化";
//        }
//        int stock = Integer.parseInt(stockStr);
//        if(stock<=0){
//            return "库存不足";
//        }
//        try {
//            Thread.sleep(5);
//        } catch (InterruptedException e) {
//            throw new RuntimeException(e);
//        }
//        //2、如果库存足够：使用i-- 库存减一 再更新到redis中
////        stock--;
//        stringRedisTemplate.opsForValue().set("sec:skuId:" + skuId, stock+"");
//        return "success";
//    }


    public String secondKill(String skuId) {
        //1、创建LUA脚本
        String script = "local stock = tonumber(redis.call('get' , KEYS[1])) " +
                "if stock>0 then redis.call('decr' ,KEYS[1]) return 1  " +
                "else return 0 end";
        //2  传入lua脚本的解析器    传入lua脚本需要的keys参数集合 传入lua脚本需要的argv参数列表
        Boolean result = stringRedisTemplate.execute(new DefaultRedisScript<Boolean>(script, Boolean.class),
                Arrays.asList("sec:skuId:" + skuId, "keys2"), "argv1", "argv2");

        return result ? "秒杀成功" : "秒杀失败";
//        System.out.println(r);

    }
    /*
        原子性问题：
            1、redis单个命令具有原子性
                如果java代码只有redis操作的单个命令，那么这个方法具有原子性
                每个访问java代码的线程生成的redis命令 交给redis都是一个个有序的执行，不会被中断
            2、如果业务中需要使用多个redis命令，并且使用了java业务代码
                java代码不加锁时，支持并发执行，导致java整个方法不具有原子性(会出现线程安全)
     */
}
